#pragma once

#include <iostream>
#include <vector>
#define BUFFER_DEFAULT_SIZE (1*1024*1024)
#define BUFFER_INCREMENT_SIZE (1*1024*1024)  // 线性增长的大小
#define BUFFER_THRESHOLD_SIZE (10*1024*1024) // 阈值

namespace lcllog
{
    class Buffer
    {
    public:
        Buffer()
        : _buffer(BUFFER_DEFAULT_SIZE)
        , _writer_idx(0)
        , _reader_idx(0)
        {}
        // 向缓冲区写入数据
        void push(const char* data, size_t len)
        {
            // 测试极限性能时，可能出现空间不够的情况
            // 扩容，动态增长
            ensureEnoughSize(len);
            // 将数据拷贝进缓冲区
            std::copy(data, data+len, &_buffer[_writer_idx]);
            // 可写位置移动
            _writer_idx += len;
        }
        void pop(size_t len) 
        { 
            if(_reader_idx + len > _writer_idx)
                return;
            _reader_idx += len; 
        }
        // 交换缓冲区
        void swap(Buffer& buf)  
        {
            _buffer.swap(buf._buffer);
            std::swap(_reader_idx, buf._reader_idx);
            std::swap(_writer_idx, buf._writer_idx);
        }
        // 初始化缓冲区
        void reset() { _reader_idx = _writer_idx = 0; }
        // 返回可读数据的起始位置
        const char* begin() { return &_buffer[_reader_idx]; }
        // 判断缓冲区是否为空
        bool empty() { return _writer_idx == _reader_idx; }
        // 可读数据的长度
        size_t readAbleSize() { return _writer_idx - _reader_idx; }
        // 可写数据的长度，只有固定大小缓冲区这个接口才有意义
        size_t writeAbleSize() { return _buffer.size() - _writer_idx; }
    private:
        void ensureEnoughSize(size_t len)
        {
            if(len <= writeAbleSize()) return;
            // 扩容
            size_t new_size = 0;
            if(_buffer.size() < BUFFER_THRESHOLD_SIZE)  
                new_size = _buffer.size() * 2 + len;
            else   
                new_size = _buffer.size() + BUFFER_INCREMENT_SIZE + len;
            
            _buffer.resize(new_size);
        }
    private:
        size_t _reader_idx; // 当前可读数据的指针 -- 本质是下标
        size_t _writer_idx; // 当前可写数据的指针
        std::vector<char> _buffer;
    };
}